#include "meshTypes.hpp"
#include "field.hpp"
#include "boundaryPatch.hpp"
#include "simulationTime.hpp"
#include "bc_slip_velocity.hpp"

namespace hms 
{

template<typename MeshType>
Slip_velocity<MeshType>::Slip_velocity(
	Field<MeshType>& v, const BoundaryPatch& p
) :
	BaseType(Type::slip_velocity, v, p),
	m_transformer {v, p}
{}

template<typename MeshType>
void Slip_velocity<MeshType>::update() const {
	Field<MeshType>& v { field() };
	const BoundaryPatch& patch { this->patch() };
	/* rectangular meshes
	 * (the non-rectangular approach works for rectangular meshes as well,
	 * but is a bit slower) */
	if constexpr (
		std::is_same_v<MeshType, UniMesh> ||
		std::is_same_v<MeshType, RectMesh>
	){
		using BL = BoundaryLocation;
		BL location { whereIs( patch, v.mesh().size() ) };

		int orthoRow { location == BL::bottom || location == BL::top ?  1 : 0 };
		
		v.ghostValues(patch).row(orthoRow) = - v.domainValues(patch).row(orthoRow);
		v.ghostValues(patch).row(!orthoRow) = v.domainValues(patch).row(!orthoRow);

	/* non-rectangular meshes (Mesh, StructMesh) */
	} else {
		/* Transform to invert sign of orthogonal component, then retransform */
		Array2Xs& vTransformed { m_transformer.transform() };
		vTransformed.row(0) *= -1;
		v.ghostValues(patch) = m_transformer.retransform();
	}
}


#define INSTANTIATE_FOR_ALL_MESHTYPES(MeshType) \
template class Slip_velocity<MeshType>;
#include "meshInstantiator.hpp"

} // end namespace hms

